package org.opens.javaskill.design.apply;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Date 2020/9/22 20:48
 * @Created by 99126
 */
public class AppServer extends Thread {

    private int port;

    private static final int DEFAULT_PORT = 12722;

    private volatile boolean start = true;

    private List<ClientHandler> clientHandlers = new ArrayList<>();

    private final ExecutorService executor = Executors.newFixedThreadPool(10);

    private ServerSocket server;

    public AppServer() {
        this(DEFAULT_PORT);
    }

    public AppServer(int port) {
        this.port = port;
    }

    @Override
    public void run() {
        try {
            this.server = new ServerSocket(port);
            while (start) {
                Socket client = server.accept();
                ClientHandler clientHandler = new ClientHandler(client);
                executor.submit(clientHandler);
                this.clientHandlers.add(clientHandler);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            this.dispose();
        }
    }

    public void stopServer() throws IOException {
        this.start = false;
        this.interrupt();
        this.server.close();
    }

    public void dispose() {
        clientHandlers.forEach(ClientHandler::stop);
        this.executor.shutdown();
    }

}

class ClientHandler implements Runnable {

    private final Socket socket;

    private volatile boolean running = true;

    public ClientHandler(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try (
                InputStream inputStream = socket.getInputStream();
                OutputStream outputStream = socket.getOutputStream();
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                PrintWriter printWriter = new PrintWriter(outputStream)
        ) {
            while (running) {
                String line = bufferedReader.readLine();
                // 当客户端主动关闭之后, 获取到的line就是null.
                if (line == null) {
                    break;
                }
                System.out.println("from client >" + line);
                printWriter.write("echo " + line + "\n");
                printWriter.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            this.stop();
        }

    }

    public void stop() {
        if (!running) {
            return;
        }

        this.running = false;
        try {
            if (this.socket != null) {
                System.out.println(this.socket + " closed");
                this.socket.close();
            }
        } catch (IOException e) {
            // 不处理
        }
    }
}

class AppServerTest {

    public static void main(String[] args) {
        AppServer server = new AppServer(13345);
        server.start();
    }

}